<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"
    />
    <title>策略模式-实现表单验证</title>
</head>
<style lang="css">
</style>

<body>
    <p>策略模式适用于：需要各种不同的规则，并且随时可替换规则，并且最终目的一致的场景，正如表单验证</p>
    <p>此处均是单条规则</p>

    <form id="registerForm">
        请输入用户名：
        <input type="text" name="userName" /> 请输入密码：
        <input type="text" name="password" /> 请输入手机号码：
        <input type="text" name="phoneNumber" />
        <button id="btn" type="button">提交</button>
    </form>

    <script type="text/javascript">
        var strategies = {
            isNonEmpty: function (value, errorMsg) {  // 不是空
                if (value === '') {
                    return errorMsg
                }
            },
            minLength: function (value, len, errorMsg) { // 最小长度
                if (value.length < len) {
                    return errorMsg
                }
            },
            isMobile: function (value, errorMsg) { // 是不是手机号
                if (!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
                    return errorMsg
                }
            }
        }
        var validatorFunc = function () {
            var validator = new Validator()
            /***************添加一些校验规则****************/
            validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空')
            validator.add(registerForm.userName, 'minLength:10', '用户名不能少于 10 位') // 添加规则非常easy
            validator.add(registerForm.password, 'minLength:6', '密码长度不能少于 6 位')
            validator.add(registerForm.phoneNumber, 'isMobile', '手机号码格式不正确')

            var errorMsg = validator.start() // 返回校验结果
            return errorMsg
        }

        var Validator = function () {
            this.validateRules = []
        }

        Validator.prototype.add = function (dom, rule, errorMsg) {
            var ary = rule.split(':') // 把 strategy 和参数分开
            this.validateRules.push(function () { // 把校验的步骤用空函数包装起来，并且放入 validateRules数组中，每一个元素都是一个方法
                var strategy = ary.shift() // 用户挑选的 strategy
                ary.unshift(dom.value) // 把 input 的 value 添加进参数列表
                ary.push(errorMsg) // 把 errorMsg 添加进参数列表

                return strategies[strategy].apply(dom, ary) // dom换成{}亦可
            });
        };

        Validator.prototype.start = function (value, stratergy, errorMsg) {

            for (var i = 0, validatorFunc; i < this.validateRules.length; i++) {

                validatorFunc = this.validateRules[i] // 将校验方法赋值给此处新建的变量validatorFunc

                var msg = validatorFunc() // 开始校验，并取得校验后的返回信息
                if (msg) { // 如果有确切的返回值，说明校验没有通过
                    return msg
                }
            }
        }

        var registerForm = document.getElementById('registerForm');
        var btn = document.querySelector('#btn')
        btn.addEventListener('click', function () {
            var errorMsg = validatorFunc() // 如果 errorMsg 有确切的返回值，说明未通过校验
            if (errorMsg) {
                alert(errorMsg)
                return false // 阻止表单提交
            }
            console.log('验证成功，提交')
        }, false)

    </script>

</body>

</html>